﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Net;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Text.RegularExpressions;
using NekoVampire.TwitterClient.Controls;
using NekoVampire.TwitterClient.Twitter;
using NekoVampire.TwitterClient.Configuration;
using NekoVampire.Extension;

namespace NekoVampire.TwitterClient.Forms
{
    public partial class Twite : Form
    {
        AccessTwitter Twitter;
        DateTime LastTime;
        UserConfiguration setting;
        Storage storage;
        ImageList imageList;
        Thread thread;
        Thread thread2;
        ListViewItemComparer ListViewItemSorter;
        Dictionary<Status, List<ListViewItemEx>> LookupListView;
        List<ListViewEx> listViews;
        Status replyStatus;
 
        public Twite()
        {
            setting = UserConfiguration.Configuration;
            if (setting.userId == "")
                new Setting(setting).ShowDialog();

            storage = new Storage();
            imageList = new ImageList();

            Twitter = AccessTwitter.Requester;
            Twitter.UserName = setting.userId;
            Twitter.Password = setting.password;

            InitializeComponent();

            LookupListView = new Dictionary<Status, List<ListViewItemEx>> { };

            listViews = new List<ListViewEx> {
                listView1,listView2
            };
            //MakeListView("test");

            this.Size = setting.mainFormSize;
            timer1.Interval = setting.Timer * 1000;
            ListViewItemSorter = setting.ListViewComparer;
            foreach (ListView listView in listViews)
            {
                listView.SmallImageList = imageList;
                listView.ListViewItemSorter = ListViewItemSorter;
                listView.BackColor = setting.BackColor;
                foreach (ColumnHeader column in listView.Columns)
                {
                    column.Width = setting.columnWidth[column.Index];
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            thread = new Thread(new ThreadStart(LoadThread));
            thread.IsBackground = true;
            thread.Start();
        }

        private void listView_SelectedIndexChanged(object sender, EventArgs e)
        {
            ListView listView = (ListView)sender;
            if (listView.SelectedItems.Count != 0 && listView.FocusedItem != null)
            {
                Status selected = ((ListViewItemEx)listView.FocusedItem).Tag;
                twitterStatusView1.Status = selected;
                twitterStatusView1.Image = storage.GetImage(selected.user.profileImageUrl);
                twitterStatusView1.ForeColor = listView.FocusedItem.ForeColor;
                if (selected.read == false)
                {
                    selected.read = true;

                    foreach (ListViewItemEx item in LookupListView[selected])
                    {
                        item.Font = setting.readFont;
                    }
                }
            }
            listView.EndUpdate();
            
            TwitterSpeed();
        }

        private void listView_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (e.Column == ListViewItemSorter.col)
                ListViewItemSorter = new ListViewItemComparer(e.Column,!ListViewItemSorter.flg);
            else
                ListViewItemSorter = new ListViewItemComparer(e.Column);
            foreach(ListView listView in listViews)
                listView.ListViewItemSorter = ListViewItemSorter;
            setting.ListViewComparer = ListViewItemSorter;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (!thread.IsAlive && ( thread2 != null ? !thread2.IsAlive : true ) )
            {
                thread.IsBackground = true;
                thread.Start();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if ((textBox1.Text != "") && (!thread.IsAlive))
            {
                thread2 = new Thread(new ThreadStart(SendUpdate));
                thread2.IsBackground = true;
                thread2.Start();
            }
            else
            {
                if (!thread.IsAlive)
                {
                    thread.IsBackground = true;
                    thread.Start();
                }
            }
        }

        protected override bool ProcessDialogKey(Keys keyData)
        {
            if ((textBox1.Focused) && (keyData == Keys.Enter) && (textBox1.Text != "") && (!thread.IsAlive))
            {
                thread2 = new Thread(new ThreadStart(SendUpdate));
                thread2.IsBackground = true;
                thread2.Start();

                return true;
            }

            return base.ProcessDialogKey(keyData);
        }

        private void 設定ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new Setting(setting).ShowDialog();
            
            Twitter.UserName = setting.userId;
            Twitter.Password = setting.password;
        }

        private void Twite_FormClosed(object sender, FormClosedEventArgs e)
        {
            thread.Abort();
            setting.Save();
        }

        public void timeLineViewAdding()
        {
            try
            {
                foreach (ListView listView in listViews)
                {
                    listView.BeginUpdate();
                }

                IEnumerable<Status> recent = storage.timeLine
                    .Where(status => !(LookupListView.Keys.Contains(status)));

                foreach (Status status in recent)
                {
                    List<ListViewItemEx> items = new List<ListViewItemEx> { };
                    ListViewItemEx item = CreateListViewItem(status);

                    item.BackColor = setting.BackColor;
                    item.ForeColor = setting.ForeColor;
                    if (setting.ViewUnfollow ? storage.notFollow.Exists(x => x == status.user.id) : false)
                    {
                        item.ForeColor = setting.UnfollowColor;
                    }

                    listView1.Items.Add(item);
                    items.Add(item);

                    if ((status.inReplyToScreenName == setting.userId)
                        || (setting.allReplies && status.text.IndexOf("@" + setting.userId) != -1)
                        || (setting.myStatusInReplies && status.user.screenName == setting.userId))
                    {
                        item = CreateListViewItem(status);
                        listView2.Items.Add(item);
                        items.Add(item);
                    }

                    LookupListView.Add(status, items);
                }
            }
            finally
            {
                foreach (ListView listView in listViews)
                {
                    listView.EndUpdate();
                }
            }

            TwitterSpeed();
            //SelectListItem(listViews[tabControl1.SelectedIndex].Items.Cast<ListViewItemEx>()
            //    .Last(x => x.Tag.read == true));

        }

        private ListViewItemEx CreateListViewItem(Status status)
        {
            ListViewItemEx Item = new ListViewItemEx();
            Item.Tag = status;
            Item.Text = "";
            if (status.user.userProtected)
                Item.Text = "!";
            Item.SubItems.Add(
                new ListViewItem.ListViewSubItem(Item, status.user.screenName)
                );
            Item.SubItems.Add(
                new ListViewItem.ListViewSubItem(Item, status.text)
                );
            Item.SubItems.Add(
                new ListViewItem.ListViewSubItem(Item, status.createdAt.ToString("yy-MM-dd HH:mm:ss"))
                );
            
            // プロフィール画像
            Item.ImageKey = status.user.profileImageUrl;
            if (!imageList.Images.ContainsKey(status.user.profileImageUrl))
            {
                imageList.Images.Add(
                    status.user.profileImageUrl,
                    storage.GetImage(status.user.profileImageUrl)
                    .GetThumbnailImage(16, 16, delegate { return false; }, IntPtr.Zero));
            }

            // 未読管理
            if (status.read == true)
            {
                Item.Font = setting.readFont;
            }
            else
            {
                Item.Font = setting.unreadFont;
            }
            return Item;
        }

        private void SelectListItem(ListViewItem item)
        {
            if (ListViewItemSorter.flg && (item.Position.Y > item.ListView.ClientSize.Height - 10 - item.Bounds.Height))
                item.ListView.EnsureVisible(item.ListView.Items.Count - 1);
            if (!ListViewItemSorter.flg && (item.Position.Y < 0))
                item.ListView.EnsureVisible(0);

            foreach (ListViewItem _item in item.ListView.SelectedItems)
            {
                _item.Selected = false;
            }
            item.ListView.SelectedIndices.Clear();
            item.Focused = true;
            item.Selected = true;
            item.ListView.EnsureVisible(item.Index);

        }

        private void GoPost(ListView sender, bool next)
        {
            if (sender.SelectedIndices.Count == 0)
                return;
            Status focused = (Status)sender.FocusedItem.Tag;

            IEnumerable<ListViewItemEx> lookup = sender.Items.Cast<ListViewItemEx>()
                .Where(x => x.Tag.user.screenName == focused.user.screenName);
            ListViewItemEx item;
            if (next)
                item = lookup
                    .OrderBy(x => x.Tag.createdAt)
                    .LastOrDefault(x => x.Tag.createdAt < focused.createdAt);
            else
                item = lookup
                    .OrderBy(x => x.Tag.createdAt)
                    .FirstOrDefault(x => x.Tag.createdAt > focused.createdAt);

            if (item != null)
                SelectListItem(item);
        }

        private void JumpUnread()
        {
            if (listView1.Items.Count != 0)
            {
                var items = listView1.Items.Cast<ListViewItemEx>()
                    .Where(x => x.Tag.read == false)
                    .QuickSort<ListViewItemEx,ListViewItemEx>(item => item, ListViewItemSorter);
                if (ListViewItemSorter.flg)
                {
                    if (items.Count() == 0)
                    {
                        SelectListItem(listView1.Items.Cast<ListViewItemEx>().Single(item => item.Index == (listView1.Items.Count - 1)));
                        return;
                    }
                    SelectListItem(items.First());
                }
                else
                {
                    if (items.Count() == 0)
                    {
                        SelectListItem(listView1.Items.Cast<ListViewItemEx>().Single(item => item.Index == 0));
                        return;
                    }
                    SelectListItem(items.Last());
                }
            }
        }
        

        private void listView_KeyDown(object sender, KeyEventArgs e)
        {
            if(!e.Alt)
            {
                if (e.KeyCode == Keys.J)
                {
                    e.Handled = true;
                    e.SuppressKeyPress = true;
                    SendKeys.Send("{DOWN}");
                    return;
                }
                if (e.KeyCode == Keys.K)
                {
                    e.Handled = true;
                    e.SuppressKeyPress = true;
                    SendKeys.Send("{UP}");
                    return;
                }
            }
            if (e.Modifiers == Keys.None)
            {
                // ModifierKeyが押されていない場合
                if ((e.KeyCode == Keys.N )||( e.KeyCode == Keys.Right))
                {
                    e.Handled = true;
                    e.SuppressKeyPress = true;
                    //GoRelPost(true);
                    return;
                }
                if ((e.KeyCode == Keys.P)||(e.KeyCode == Keys.Left))
                {
                    e.Handled = true;
                    e.SuppressKeyPress = true;
                    //GoRelPost(False);
                    return;
                }
                if (e.KeyCode == Keys.OemPeriod)
                {
                    e.Handled = true;
                    e.SuppressKeyPress = true;
                    //GoAnchor();
                    return;
                }
                if ((e.KeyCode == Keys.Space)||(e.KeyCode == Keys.ProcessKey))
                {
                    e.Handled = true;
                    e.SuppressKeyPress = true;
                    JumpUnread();
                    return;
                }
                if ((e.KeyCode == Keys.Enter)||(e.KeyCode == Keys.Return))
                {
                    e.Handled = true;
                    e.SuppressKeyPress = true;
                    listView1_DoubleClick(sender, null);
                    return;
                }
                if (e.KeyCode == Keys.L)
                {
                    e.Handled = true;
                    e.SuppressKeyPress = true;
                    GoPost((ListView)sender, false);
                    return;
                }
                if (e.KeyCode == Keys.H)
                {
                    e.Handled = true;
                    e.SuppressKeyPress = true;
                    GoPost((ListView)sender, true);
                    return;
                }
                if ((e.KeyCode == Keys.Z)||( e.KeyCode == Keys.Oemcomma ))
                {
                    e.Handled = true;
                    e.SuppressKeyPress = true;
                    GoPost((ListView)sender, true);
                    return;
                }
            }
        }

        private void 既読にするToolStripMenuItem_Click(object sender, EventArgs e)
        {
            readSelectedItem(listViews[tabControl1.SelectedIndex]);
        }

        private void readSelectedItemButton_Click(object sender, EventArgs e)
        {
            readSelectedItem(listViews[tabControl1.SelectedIndex]);
        }

        private void readSelectedItem(ListView listView)
        {
            IEnumerable<Status> reading = listView.SelectedItems.Cast<ListViewItemEx>()
                .Where(p => p.Tag.read == false)
                .Select(p => p.Tag);
            listView.BeginUpdate();
            try
            {
                lock (storage)
                {
                    foreach (Status selectStatus in reading)
                    {
                        selectStatus.read = true;

                        foreach (ListViewItem item in LookupListView[selectStatus])
                        {
                            item.Font = setting.readFont;
                        }
                    }
                }
            }
            finally
            {
                listView.EndUpdate();
            }
        }

        private void listView1_DoubleClick(object sender, EventArgs e)
        {
            ListViewEx listView = (ListViewEx)sender;

            IEnumerable<Status> replies = listView.SelectedItems.Cast<ListViewItemEx>()
                .Select(item => item.Tag);

            foreach(Status reply in replies)
            {
                if (new Regex(@"^(\. )?@(\w)").IsMatch(textBox1.Text))
                {
                    replyStatus = null;

                    if (textBox1.Text.IndexOf("@" + reply.user.screenName) != -1)
                    {
                        continue;
                    }
                    else if (textBox1.Text.IndexOf(". ") == 0)
                    {
                        textBox1.Text = textBox1.Text.Insert(2, "@" + reply.user.screenName + " ");
                    }
                    else
                    {
                        textBox1.Text = textBox1.Text.Insert(0, ". @" + reply.user.screenName + " ");
                    }
                }
                else
                {
                    textBox1.Text = textBox1.Text.Insert(0, "@" + reply.user.screenName + " ");
                    replyStatus = reply;
                }
            }
        }

        private void twitterStatusView1_LinkClicked(object sender, TwitterStatusView.LinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start(e.Url);
        }

        private void twitterStatusView1_ScreenNameClicked(object sender, TwitterStatusView.ScreenNameClickedEventArgs e)
        {
            ShowUser(e.Name);
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            CreateFav(listViews[tabControl1.SelectedIndex]);
        }

        private void ふぁぼるToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CreateFav(listViews[tabControl1.SelectedIndex]);
        }

        private void favariteから削除するToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DestroyFav(listViews[tabControl1.SelectedIndex]);
        }

        private void バージョン情報ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new Version().Show();
        }

        private void webサイトへToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://");
        }

        private void 未読にするToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.Visible = true;
            this.Activate();
        }

        private void Twite_FormClosing(object sender, FormClosingEventArgs e)
        {
            setting.mainFormSize = this.Size;
            if (e.CloseReason == CloseReason.UserClosing)
            {
                this.Visible = false;
                e.Cancel = true;
            }
        }

        private void 閉じるToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Visible = false;
        }

        private void 終了ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void twitterStatusView1_PictureClick(object sender, EventArgs e)
        {
            Status status = ((TwitterStatusView)sender).Status;
            if(status != null)
                ShowUser(status.user.screenName);
        }

        private User ShowUser(string userName)
        {
            User window = new User(Twitter, storage);
            window.Show(userName);
            return window;
        }

        private void TwitterSpeed()
        {
            try
            {
                int all = storage.timeLine.Count;
                int unread = storage.timeLine.Count(status => status.read == false);
                var tl = storage.timeLine.Where(status => status.createdAt > DateTime.Now.AddHours(-1));
                int tl_speed = tl.Count();
                int speed = tl.Count(status => status.user.screenName == setting.userId);

                toolStripStatusLabel2.Text = "[" + unread + "/" + all + "] [時速: 投" + speed + " 流" + tl_speed + "]";
            }
            catch (InvalidOperationException)
            {
            }
        }

        private void listView1_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
        {
            if (setting.columnWidth[e.ColumnIndex] != ((ListView)sender).Columns[e.ColumnIndex].Width)
            {
                setting.columnWidth[e.ColumnIndex] = ((ListView)sender).Columns[e.ColumnIndex].Width;

                foreach (ListView listView in listViews)
                {
                    listView.Columns[e.ColumnIndex].Width = setting.columnWidth[e.ColumnIndex];
                }
            }
        }

        private void すべて既読にするToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var unread = LookupListView
                .Where(lookup => lookup.Key.read == false);
            foreach (var items in unread)
            {
                items.Key.read = true;
                foreach (ListViewItemEx item in items.Value)
                {
                    item.Font = setting.readFont;
                }
            }
        }

        private ListViewEx MakeListView(string title)
        {
            ListViewEx listView = new ListViewEx();

            foreach (ColumnHeader ch in listView1.Columns)
            {
                listView.Columns.Add((ColumnHeader)ch.Clone());
            }
            listView.ContextMenuStrip = this.listViewContextMenu;
            listView.Dock = System.Windows.Forms.DockStyle.Fill;
            listView.FullRowSelect = true;
            listView.ImeMode = System.Windows.Forms.ImeMode.Disable;
            listView.Location = new System.Drawing.Point(3, 3);
            listView.Name = "listView1";
            listView.Size = new System.Drawing.Size(676, 274);
            listView.Sorting = System.Windows.Forms.SortOrder.Ascending;
            listView.TabIndex = 2;
            listView.UseCompatibleStateImageBehavior = false;
            listView.View = System.Windows.Forms.View.Details;
            listView.ColumnWidthChanged += new System.Windows.Forms.ColumnWidthChangedEventHandler(this.listView1_ColumnWidthChanged);
            listView.SelectedIndexChanged += new System.EventHandler(this.listView_SelectedIndexChanged);
            listView.DoubleClick += new System.EventHandler(this.listView1_DoubleClick);
            listView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listView_ColumnClick);
            listView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listView_KeyDown);

            TabPage tab = new TabPage();
            tab.Dock = System.Windows.Forms.DockStyle.Fill;
            tab.Location = new System.Drawing.Point(4, 4);
            tab.Padding = new System.Windows.Forms.Padding(3);
            tab.Size = new System.Drawing.Size(682, 276); ;
            tab.Text = title;

            this.tabControl1.Controls.Add(tab);
            tab.Controls.Add(listView);
            listViews.Add(listView);

            return listView;
        }
    }

}
